package org.opens.javaskill.thread.threadLocal;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * @Date 2020/9/16 20:52
 * @Created by 99126
 */
public class MyThreadLocalDemo {

    private final static Random random = new Random(System.currentTimeMillis());

    public static void main(String[] args) throws InterruptedException {
        MyThreadLocal<String> threadLocal = new MyThreadLocal<String>(){
            @Override
            public String initValue() {
                return "init";
            }
        };

        Thread thread1 = new Thread(() -> {
            threadLocal.set(Thread.currentThread().getName());
            try {
                Thread.sleep(random.nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " " + threadLocal.get());
        }, "t1");

        Thread thread2 = new Thread(() -> {
            threadLocal.set(Thread.currentThread().getName());
            try {
                Thread.sleep(random.nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " " + threadLocal.get());
        }, "t2");
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();

        System.out.println("===");
        System.out.println(Thread.currentThread().getName() + " " + threadLocal.get());
    }

}

/**
 * 说明:
 * <p>自己实现的一个简单的ThreadLocal复制版</p>
 * @param <T>   ThreadLocal所保存的值的类型
 */
class MyThreadLocal<T> {

    /**
     * 说明:
     * 1. 底层存储使用Thread实例为key, 使用设置的泛型为value.
     */
    private final Map<Thread, T> storage = new HashMap<>();

    public void set(T value) {
        synchronized (this) {
            Thread thread = Thread.currentThread();
            storage.put(thread, value);
        }
    }

    public T get() {
        synchronized (this) {
            Thread thread = Thread.currentThread();
            T value = storage.get(thread);
            if (value == null) {
                return initValue();
            }
            return value;
        }
    }

    public T initValue() {
        return null;
    }

}

